/*
 * To change this template, choose Tools | Templates
 * and open the template in the editor.
 */
package com.smart.service.search;

import com.gargoylesoftware.htmlunit.BrowserVersion;
import com.gargoylesoftware.htmlunit.ElementNotFoundException;
import com.gargoylesoftware.htmlunit.FailingHttpStatusCodeException;
import com.gargoylesoftware.htmlunit.Page;
import com.gargoylesoftware.htmlunit.WebClient;
import com.gargoylesoftware.htmlunit.html.HtmlAnchor;
import com.gargoylesoftware.htmlunit.html.HtmlButton;
import com.gargoylesoftware.htmlunit.html.HtmlDivision;
import com.gargoylesoftware.htmlunit.html.HtmlForm;
import com.gargoylesoftware.htmlunit.html.HtmlImage;
import com.gargoylesoftware.htmlunit.html.HtmlPage;
import com.gargoylesoftware.htmlunit.html.HtmlTextInput;
import com.smart.service.util.Logging;


import java.io.IOException;
import java.net.MalformedURLException;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

/**
 * <div class="hotel_description"> 
 * <div class="main_description" id="219475_noChart"> <h3>
 * <a id="lnk_hotelTitle_219475" 
 * 		title="Veja a descrição completa, fotos, mapas e todos os tipos de quarto disponíveis" 
 * 		class="hotelNameLink" 
 * 		href="/hotel/details.html?pa=2&pn=1&ps=2&tab=description&destinationId=1634634&hotelId=219475&arrivalDate=29-07-2011&departureDate=31-07-2011&rooms[0].numberOfAdults=2&roomno=1&validate=false&previousDateful=false&reviewOrder=date_newest_first">
 * 	Mercure Campinas
 * </a>
 * </h3> 
 * <a id="lnk_hotelDetailsPhoto_219475" 
 * 		href="/hotel/details.html?pa=2&pn=1&ps=2&tab=description&destinationId=1634634&hotelId=219475&arrivalDate=29-07-2011&departureDate=31-07-2011&rooms[0].numberOfAdults=2&roomno=1&validate=false&previousDateful=false&reviewOrder=date_newest_first"
 * 		class="select"> 
 * <img class="hotel_picture" 
 * 		id="sfThumb219475" 
 * 		src="http://exp.cdn-hotels.com/hotels/2000000/1060000/1056800/1056712/1056712_67_t.jpg"
 * 		alt="Mercure Campinas" /> 
 * </a> 
 * <div class="ratings"> 
 * <div class="starRating">
 * <a href="/customer_care/star_rating.html" 
 * 		id="lnk_starRatingPopup219475"
 * 		title="3,5 estrelas">
 * <span class="sprites_star_rating rate_7 hcomPopup">3,5 estrelas</span> </a>
 * </div> 
 * <div class="bar_rating"> 
 * <a class="guestRatingLink"	id="lnk_hotelDetailsRatings_219475" 
 * 		href="/hotel/details.html?pa=2&pn=1&ps=2&tab=reviews&destinationId=1634634&hotelId=219475&arrivalDate=29-07-2011&departureDate=31-07-2011&rooms[0].numberOfAdults=2&roomno=1&validate=false&previousDateful=false&reviewOrder=date_newest_first"
 * 		title=Avaliação de 5 dos clientes do hotels.com. Clique para ver os comentários dos clientes deste hotel"> 
 * <strong>3,7<span class="max_rating"> / 5</span></strong> <span
 * class="sprites_guest_rating5">
 * 
 * <span class="indicator rate_4"></span> <span class="indicator_holder"></span>
 * </span> </a> <span> de <a id="lnk_hotelDetailsRatingsCount_219475" href=
 * "/hotel/details.html?pa=2&pn=1&ps=2&tab=reviews&destinationId=1634634&hotelId=219475&arrivalDate=29-07-2011&departureDate=31-07-2011&rooms[0].numberOfAdults=2&roomno=1&validate=false&previousDateful=false&reviewOrder=date_newest_first"
 * title=
 * "Avaliação de 5 dos clientes do hotels.com. Clique para ver os comentários dos clientes deste hotel"
 * >3 avaliações de hóspedes</a></span> </div> </div>
 * 
 * <div class="desc area_data"> Campinas</div> <div
 * class="phonenumber_container"> <div class="clear-both"><!-- IE6 --></div>
 * <div> <span id="srp_phone_tfn_2">0800-891-3841</span> </div> <div
 * class="clear-both"><!-- IE6 --></div>
 * 
 * </div> </div> <div id="TH_IS_2" class=" bottom_offer"><span
 * style="display: none;"><!-- IE6 --></span></div> <!--[if lte IE
 * 6]><div></div><![endif]--> <div class="pricing"> <div class="price">
 * <span>R$250</span> <span class="disclaimer">
 * 
 * <span class="inclusive_priceinfo">preço médio da diária</span></span> </div>
 * <p class="select">
 * <a id="lnk_Select_219475" href=
 * "/hotel/details.html?pa=2&pn=1&ps=2&tab=description&destinationId=1634634&hotelId=219475&arrivalDate=29-07-2011&departureDate=31-07-2011&rooms[0].numberOfAdults=2&roomno=1&validate=false&previousDateful=false&reviewOrder=date_newest_first"
 * > Selecionar</a>
 * </p>
 * </div> <div class="toolbar">
 * 
 * </div> </div>
 * 
 * 
 * @author arthur
 */
public class SearchWebHotelService {

	private static final Logging LOGGER = Logging
			.getLogger(SearchWebHotelService.class.getName());

	private final WebClient webClient = new WebClient(
			BrowserVersion.INTERNET_EXPLORER_8);
	// FORM
	public static final String searchForm = "searchForm";
	public static final String txt_destination = "txt_destination";
	public static final String txt_arrival = "txt_arrival";
	public static final String txt_departure = "txt_departure";
	public static final String btn_search_submit = "btn_search_submit";
	// URL
	private static final String page_url = "http://www.hoteis.com";
	// DESCRI
	//public static final String _codeHotel2 = "hotelId";
	public static final String _departureDate = "departureDate";
	public static final String _arrivalDate = "arrivalDate";
	public static final String _destinationId = "destinationId";
	//
	private static Pattern p1 = Pattern.compile("(hotelId=)(\\d+)(&)");
	private static Pattern p2 = Pattern.compile("(>R\\$)(\\d+)(<)");
	private static Pattern p3 = Pattern
			.compile("(>)(\\d,?\\d?)(\\sestrelas</span>)");
	//
	public static final String _codeHotel = "CodeHotel";
	public static final String _name = "Name";
	public static final String _averagePrice = "AveragePrice";
	public static final String _quality = "Quality";
	public static final String _linkSelection = "LinkSelection";
	public static final String _linkImage = "LinkImage";
	private static final String _div_hotel_description = "//div[@class='hotel_description']";

	/**
     * 
     */
	public void end() {
		LOGGER.debug("end");
		webClient.closeAllWindows();
	}

	/**
	 * keys Id Nome PrecoMedio Qualidade LinkSelection DepartureDate ArrivalDate
	 * DestinationId LinkImage
	 * 
	 * @param destination
	 * @param arrival
	 * @param departure
	 * @return
	 */
	public List<Map<String, String>> searchHotel(String destination,
			String arrival, String departure) {
		LOGGER.debug("searchHotel");
		List<Map<String, String>> retorno = null;
		try {
			HtmlPage page2 = searchHotel1(getPageInit(), destination, arrival,
					departure);
			assert page2 != null : "page2 is null";
			List<?> divs = searchHotel2(page2);
			retorno = searchHotel3(divs);
		} catch (Exception ex) {
			LOGGER.error("searchHotel", ex);
		}
		return retorno;
	}

	/**
	 * 
	 * @param destination
	 * @param arrival
	 * @param departure
	 * @return
	 * @throws IOException
	 * @throws MalformedURLException
	 * @throws FailingHttpStatusCodeException
	 * @throws Exception
	 */
	public HtmlPage searchHotel1(final HtmlPage page1, String destination,
			String arrival, String departure)
			throws FailingHttpStatusCodeException, MalformedURLException,
			IOException {
		LOGGER.debug("searchHotel1");
		assert page1 != null : "page1 is null";
		assert destination != null : "destination is null";
		assert !destination.trim().equals("") : "destination is empity";
		final HtmlForm form = (HtmlForm) page1.getElementById(searchForm);
		final HtmlTextInput textDestination = form
				.getElementById(txt_destination);
		textDestination.setValueAttribute(destination);

		if (arrival != null && !arrival.trim().equals("")) {
			final HtmlTextInput textArrival = form.getElementById(txt_arrival);
			// textArrival.setValueAttribute(arrival);
		}
		if (departure != null && !departure.trim().equals("")) {
			final HtmlTextInput textDeparture = form
					.getElementById(txt_departure);
			// textDeparture.setValueAttribute(departure);
		}
		final HtmlButton buttonSearch = (HtmlButton) form
				.getElementById(btn_search_submit);
		HtmlPage page2 = null;
		buttonSearch.focus();

		page2 = buttonSearch.click();

		return page2;
	}

	public HtmlPage getPageInit() throws FailingHttpStatusCodeException,
			MalformedURLException, IOException {
		final Page page = webClient.getPage(page_url);
		assert page instanceof HtmlPage : "page isn't instance of HtmlPage it's "
				+ page.getClass().getName();
		final HtmlPage page1 = (HtmlPage) page;
		return page1;
	}

	/**
	 * recebe retorno de searchHotel1 e devolve list das div dos hoteis
	 * 
	 * @param page
	 * @return
	 * @throws Exception
	 */
	public List<?> searchHotel2(final HtmlPage page) {
		LOGGER.debug("searchHotel2");
		final List<?> divs = page.getByXPath(_div_hotel_description);
		return divs;
	}

	/**
	 * 
	 * @param divs
	 * @return
	 * @throws Exception
	 */
	public List<Map<String, String>> searchHotel3(List<?> divs) {
		LOGGER.debug("searchHotel3");
		List<Map<String, String>> listHotel = new ArrayList<Map<String, String>>();
		for (int i = 0; i < divs.size(); i++) {
			HtmlDivision div_hotel_description = (HtmlDivision) divs.get(i);
			String xml = div_hotel_description.asXml().replaceAll("\\s", "");
			Matcher m1 = p1.matcher(xml);
			if (m1.find()) {
				Map<String, String> to = generateMapHotel(
						div_hotel_description, xml, m1);
				if(to != null){
					listHotel.add(to);	
				}
			} else {
				System.out.println(xml);
			}

		}
		return listHotel;

	}

	private Map<String, String> generateMapHotel(
			HtmlDivision div_hotel_description, String xml, Matcher m1) {
		Map<String, String> to = new HashMap<String, String>();
		String id = addCodeHotel(m1, to);
		setAveragePrice(xml, to);
		setQuality(xml, to);
		final HtmlAnchor link = getLink(div_hotel_description, id);
		assert link != null;
		searchHotel4(to, link);
		final HtmlImage imagem = getImage(to, link);
		if(imagem != null){
			setName(to, imagem);
			setImagem(to, imagem);
		}else{
			to = null;
		}
		return to;
	}

	private String addCodeHotel(Matcher m1, Map<String, String> to) {
		String id = m1.group(2);
		to.put(_codeHotel, id);
		return id;
	}

	private HtmlAnchor getLink(HtmlDivision div_hotel_description, String id) {
		final HtmlAnchor link = (HtmlAnchor) div_hotel_description
				.getElementById("lnk_hotelTitle_" + id);
		return link;
	}

	private void setQuality(String xml, Map<String, String> to) {
		Matcher m3 = p3.matcher(xml);
		if (m3.find()) {
			// need to fix this
			to.put(_quality, m3.group(2));
		} else {
			to.put(_quality, "0.0");
		}
	}

	private void setAveragePrice(String xml, Map<String, String> to) {
		Matcher m2 = p2.matcher(xml);
		if (m2.find()) {
			to.put(_averagePrice, m2.group(2));
		} else {
			to.put(_averagePrice, "0.0");
		}
	}

	/**
	 * 
	 * @param to
	 * @param link
	 * @throws Exception
	 */
	private void searchHotel4(Map<String, String> to, HtmlAnchor link) {
		LOGGER.debug("searchHotel4");
		String linkDesc1 = link.getHrefAttribute();
		assert linkDesc1 != null;
		to.put(_linkSelection, linkDesc1);
		String[] linkParameters = linkDesc1.split("&");
		for (String param : linkParameters) {
			String[] info = param.split("=");
			if (info.length == 2) {
				String key = info[0].trim();
				String value = info[1].trim();
				if (key.equals(_departureDate)) {
					to.put(_departureDate, value);
				} else if (key.equals(_arrivalDate)) {
					to.put(_arrivalDate, value);
				} else if (key.equals(_destinationId)) {
					to.put(_destinationId, value);
				}
			}
		}
	}

	/**
	 * 
	 * Pode ser neste formato
	 * <img alt="Quality Resort And Convention Center" src=
	 * "http://exp.cdn-hotels.com/hotels/2000000/1460000/1457600/1457535/1457535_24_t.jpg"
	 * id="sfThumb241862" class="hotel_picture">
	 * 
	 * ou neste
	 * 
	 * <img alt="Tryp Campinas" src="/13/hotels/1000000/920000/912800/912791/hcom_912791_28_t.jpg" 
	 * id="sfThumb211682" class="hotel_picture imagePopDivThumb">
	 * 
	 * 
	 * @param to
	 * @param imagem
	 */
	private void setImagem(Map<String, String> to, HtmlImage imagem) {
		try {
			to.put(_linkImage, imagem.getSrcAttribute());
		} catch (Exception ex) {
			to.put(_linkImage, "Sem Image");
		}

	}

	private void setName(Map<String, String> to, HtmlImage imagem) {
		try {
			to.put(_name, imagem.getAltAttribute());
		} catch (Exception ex) {
			to.put(_name, "Sem Nome");
		}

	}

	/**
	 * <img alt="Quality Resort And Convention Center" src=
	 * "http://exp.cdn-hotels.com/hotels/2000000/1460000/1457600/1457535/1457535_24_t.jpg"
	 * id="sfThumb241862" class="hotel_picture">
	 * 
	 */
	private HtmlImage getImage(Map<String, String> to, HtmlAnchor link) {
		HtmlImage imagem = null;
		try{
			imagem = (HtmlImage) link.getElementById("sfThumb" + to.get(_codeHotel));
		}catch(ElementNotFoundException e){
			
		}
		return imagem;
	}
}
